#include <retro.h>
#include "retro.creator.h"

using namespace Retro::Creator::GUI;

#define SCROLL_MARGIN       5
#define SCROLL_SIZE         10
#define CHECKERBOARD_SIZE   16

TexturePreview::TexturePreview()
{
  texture = NULL;
  grab    = NULL;
}

TexturePreview::~TexturePreview()
{
}

VOID    TexturePreview::onControlPaint(Controls::ControlPaintEvent& iEvent)
{
  if (texture)
  {
    Geom::Rect client = Geom::Rect::fromClient(*this);

    iEvent.graphics.SetCompositingQuality(Gdip::CompositingQualityHighSpeed);
    iEvent.graphics.SetSmoothingMode(Gdip::SmoothingModeHighSpeed);
    iEvent.graphics.SetInterpolationMode(Gdip::InterpolationModeBilinear);

    // draw checkerboard
    Drawing::drawCheckerboard(
      CHECKERBOARD_SIZE,
      Gdip::Rect(0, 0, iEvent.bounds.Width, iEvent.bounds.Height),
      iEvent.graphics);

    // draw texture
    iEvent.graphics.DrawCachedBitmap(
      &Gdip::CachedBitmap(texture, &iEvent.graphics),
      offset.Width < iEvent.bounds.Width ?
        (iEvent.bounds.Width - offset.Width) / 2 :
        offset.X,
      offset.Height < iEvent.bounds.Height ?
        (iEvent.bounds.Height - offset.Height) / 2 :
        offset.Y);

    // draw scrollbars
    if (isMouseOver())
    {
      iEvent.graphics.SetPixelOffsetMode(Gdip::PixelOffsetModeHalf);

      if (ptMin.x < 0)
      {
        INT cxScroll = (INT)(iEvent.bounds.Width * (REAL)
          (iEvent.bounds.Width - SCROLL_MARGIN * 2) / offset.Width);

        Gdip::Rect scroll(
          (INT)(SCROLL_MARGIN + offset.X * (REAL)(iEvent.bounds.Width -
          cxScroll - SCROLL_SIZE - SCROLL_MARGIN * 2) / ptMin.x),
          iEvent.bounds.Height - SCROLL_SIZE - SCROLL_MARGIN,
          cxScroll, SCROLL_SIZE);

        iEvent.graphics.FillRectangle(&Gdip::SolidBrush(0x7F000000), scroll);
        iEvent.graphics.DrawRectangle(&Gdip::Pen(0xFFFFFFFF), scroll);
      }

      if (ptMin.y < 0)
      {
        INT cyScroll = (INT)(iEvent.bounds.Height * (REAL)
          (iEvent.bounds.Height - SCROLL_MARGIN * 2) / offset.Height);

        Gdip::Rect scroll(
          iEvent.bounds.Width - SCROLL_SIZE - SCROLL_MARGIN,
          (INT)(SCROLL_MARGIN + offset.Y * (REAL)(iEvent.bounds.Height -
          cyScroll - SCROLL_SIZE - SCROLL_MARGIN * 2) / ptMin.y),
          SCROLL_SIZE, cyScroll);

        iEvent.graphics.FillRectangle(&Gdip::SolidBrush(0x7F000000), scroll);
        iEvent.graphics.DrawRectangle(&Gdip::Pen(0xFFFFFFFF), scroll);
      }
    }
  }
  else
  {
    Gdip::StringFormat format;

    format.SetLineAlignment(Gdip::StringAlignmentCenter);
    format.SetAlignment(Gdip::StringAlignmentCenter);

    iEvent.graphics.DrawString(
      _T("No associated image"), -1,
      &Gdip::Font(_T("Arial"), 12, Gdip::FontStyleBold),
      Geom::rectToFloat(iEvent.bounds),
      &format,
      &Gdip::SolidBrush(0x7F000000));
  }
}

VOID    TexturePreview::onMouseDown(Event::MouseEvent& iEvent)
{
  grab    = TRUE;
  grabPt  = iEvent.point;
}

VOID    TexturePreview::onMouseUp(Event::MouseEvent& iEvent)
{
  grab    = FALSE;
}

VOID    TexturePreview::onMouseMove(Event::MouseEvent& iEvent)
{
  if (grab)
  {
    offset.X += (iEvent.x - grabPt.x) * 2;
    offset.Y += (iEvent.y - grabPt.y) * 2;
    offset.X = max(ptMin.x, offset.X);
    offset.Y = max(ptMin.y, offset.Y);
    offset.X = min(0, offset.X);
    offset.Y = min(0, offset.Y);

    grabPt = iEvent.point;
    invalidate(FALSE);
  }
}

VOID    TexturePreview::onMouseEnter(Event::MouseEvent& iEvent)
{
  Geom::Rect client = Geom::Rect::fromClient(*this);

  ptMin.x = client.right - offset.Width;
  ptMin.y = client.bottom - offset.Height;
  ptMin.x = min(0, ptMin.x);
  ptMin.y = min(0, ptMin.y);

  SetCursor(LoadCursor(NULL, IDC_HAND));
  invalidate(FALSE);
}

VOID    TexturePreview::onMouseLeave()
{
  SetCursor(LoadCursor(NULL, IDC_ARROW));
  invalidate(FALSE);
}

VOID    TexturePreview::setTexture(Gdip::Bitmap* value)
{
  if (texture = value)
  {
    offset = Gdip::Rect(0, 0, texture->GetWidth(), texture->GetHeight());
  }
}
